import { isArray, isString, trim, isEmpty } from 'lodash';
import Rules from './rules'
import Messages from './messages'

/**
 * 验证器对象
 */
const verify = {
    // 传入的自定义验证对象
    ruleList: null,

    // 传入的所有需要验证的数据对象
    fieldsData: null,

    // 特殊规则
    specialRules: ['confirmed'],

    // 必须验证字段
    mustRules: 'required',

    // 当前被验证的字段名
    currentField: '',

    // 当前被验证的字段值
    currentValue: '',

    // 当前字段的验证规则列表
    currentRules: '',

    // 规则的错误提示信息列表
    currentRulesMessage: '',

    // 当前的字段展示名称
    currentAttrName: '',

    // 验证结果集
    verifyResult: {},

    // 替换的模板
    replaceTmp: [
        ':attribute',
        ':field',
        ':minLength',
        ':maxLength',
    ],

    exec(fields, rulesList) {
        this.fieldsData = fields
        this.ruleList = rulesList
        this.verifyResult = {}

        for (let item of Object.entries(fields)) {
            // 分解要验证的字段名和值
            let [field, data] = item
            // 遍历规则
            for (let rule of rulesList.rules) {
                if (this.isLegal(rule[field])) {
                    this.initVerifyData(field, data, rule)
                    let result = this.doVerify()
                    // 执行验证，如果无错误就返回null
                    if (result) {
                        Object.assign(this.verifyResult, result)
                    }
                }
            }
            
        }

        return this
    },

    /**
     * 得到验证结果
     */
    getResult() {
        return this.verifyResult
    },

       /**
     * 根据字段名，获取错误信息
     * @param {*} fieldName 
     */
    getErrorByField(fieldName) {
        if (this.verifyResult && this.verifyResult.hasOwnProperty(fieldName)) {
            return this.verifyResult[fieldName]
        }

        return []
    },

    /**
     * 获取第一组错误对象
     */
    getFirstError() {
        if (!isEmpty(this.verifyResult)) {
            for (let item in this.verifyResult) {
                return {[item]: this.verifyResult[item]}
            }
        }
        
        return this.verifyResult
    },

    /**
     * 根据字段名，获取该字段是否有错误
     * @param {*} fieldName 
     */
    hasErrorByField(fieldName) {
        return this.verifyResult.hasOwnProperty(fieldName)
    },

    /**
     * 是否所有校验都通过
     */
    isSuccess() {
        return isEmpty(this.verifyResult)
    },

    /**
     * 一次性标记所有字段
     * @param {*} fields 
     */
    getErrorsFlag(fields) {
        for (let flag of Object.keys(fields)) {
            fields[flag] = this.verifyResult.hasOwnProperty(flag)
        }
        
        return fields
    },

    /**
     * 把重要数据，放到属性上
     * @param {*} field 
     * @param {*} value 
     * @param {*} rules 
     */
    initVerifyData(field, value, rule) {
        this.currentField = trim(field)
        this.currentValue = trim(value)
        this.currentRules = rule[field]
        this.currentAttrName = this.getRuleAttribute(field)
    },

    /**
     * 判断规则合法性
     * @param {*} data 
     */
    isLegal(data) {
        return data && isArray(data) && data.length > 0
    },

    /**
     * 执行验证
     */
    doVerify() {
        let hasError = false
        let info = {
            [this.currentField]: [], 
        }

        // 当前字段的所有规则进行验证一遍
        for (let rule of this.currentRules) {
            let ruleInfo = this.parseRule(rule)
            // 是否验证通过
            if (this.isPass(ruleInfo)) {
                continue
            }

            hasError = true
            // 如果验证失败，则处理
            this.currentRulesMessage = this.getRuleMessage(ruleInfo.name)
            info[this.currentField].push(this.setErrorMessage(ruleInfo.param))
        }

        return hasError ? info : false
    },

    /**
     * 解析规则
     * @param {*} ruleArr 
     */
    parseRule(rule) {
        let hasParams = rule.includes(':')
        let retObj = {name: rule, param: null}
        let arr = []
        
        // 以':'来分割规则名称和规则参数
        if (hasParams) {
            arr = rule.split(':')
            retObj.name = arr[0]
            retObj.param = arr[1]
        }

        // 以','来分割多个参数
        if (retObj.param && retObj.param.includes(',')) {
            arr = retObj.param.split(',')
            retObj.param = arr
        }

        if (this.specialRules.includes(retObj.name) && this.fieldsData[retObj.param]) {
            retObj.param = this.fieldsData[retObj.param]
        }
        
        return retObj
    },

    /**
     * 执行验证操作
     * @param {*} ruleInfo 
     */
    rulesVerify(ruleInfo) {
        if (Rules.hasOwnProperty(ruleInfo.name)) {
            return Rules[ruleInfo.name](this.currentValue, ruleInfo.param)
        }
        
        return true
    },

    /**
     * 是否验证通过
     */
    isPass(ruleInfo) {
        // 如果没有required，并且数据为空，则通过
        if (!this.currentRules.includes(this.mustRules) && '' === this.currentValue) {
            return true
        }

        // 执行验证
        if (this.rulesVerify(ruleInfo)) {
            return true
        }

        return false
    },
    
    /**
     * 解析字段展示名
     */
    getRuleAttribute(field) {
        let attrName = field

        if (this.ruleList.attribute && this.ruleList.attribute[field]) {
            attrName = this.ruleList.attribute[field]
        }
        
        return attrName
    },

    /**
     * 解析规则中的自定义提示信息，或者默认提示信息
     */
    getRuleMessage(ruleName) {
        let message = Messages[ruleName]
        
        if (this.ruleList.messages && this.ruleList.messages[this.currentField] && this.ruleList.messages[this.currentField][ruleName]) {
            message = this.ruleList.messages[this.currentField][ruleName]
        }
        
        return message
    },

    /**
     * 处理错误数据
     */
    setErrorMessage(param) {
        for (let i=0; i<this.replaceTmp.length; i++) {
            if (this.currentRulesMessage.includes(this.replaceTmp[i])) {
                let methodName = this.setTmpMethondName(this.replaceTmp[i])
                this.currentRulesMessage = this[methodName](this.replaceTmp[i], param)
            }
        }

        return this.currentRulesMessage
    },

    replaceAttributeTemplate(tmp, options=[]) {
        return this.currentRulesMessage.replace(tmp, this.currentAttrName)
    },

    replaceMinlengthTemplate(tmp, options=[]) {
        if (options) {
            if (isArray(options) && options.length >= 1) {
                return this.currentRulesMessage.replace(tmp, options[0])
            }

            if (isString(options)) {
                return this.currentRulesMessage.replace(tmp, options)
            }
        }
        
        return this.currentRulesMessage
    },

    replaceMaxlengthTemplate(tmp, options=[]) {
        let repVal = ''
    
        if (options) {
            if (isArray(options) && options.length > 0) {
                if (1 === options.length) {
                    repVal = options[0]
                } else {
                    repVal = options[1]
                }
            }

            if (isString(options)) {
                repVal = options
            }

            return this.currentRulesMessage.replace(tmp, repVal)
        }
        
        return this.currentRulesMessage
    },

    replaceFieldTemplate(tmp, options=[]) {
        return this.currentRulesMessage.replace(tmp, this.currentAttrName)
    },

    /**
     * 设置方法名称
     * @param {*} tmpName 
     */
    setTmpMethondName(tmpName) {
        let newName = tmpName.replace(':', '')
        newName = newName.toLowerCase().replace(/( |^)[a-z]/g, (L) => L.toUpperCase())
        return 'replace' + newName + 'Template'
    },
}

export default verify



  